	title	"tShell logon module version 0.60"
;
;	(c) 1985 S. Kluger, All Rights Reserved.
;	This is the logon module for tShell. It
;	should be copied to 31A:WARMSTRT.AUT.
;
;	History:
;	12/14/85	started, completed default logon code,
;			completed userid/password entry routine.
;	12/15/85	ready for extensive testing!
;	12/20/85	added drive access display
;	12/21/85	added priv level display
;	12/22/85	added logoff before logon, made DELETED flag work
;	01/01/86	changed for USRSUP
;	01/04/86	started clock inop code
;
cr	equ	0dh
lf	equ	0ah
cfunc	equ	5
tfunc	equ	50h
jconv	equ	10958
tries	equ	4		; up to 4 missed logons in a row
wait	equ	60		; number of seconds to delay after n tries
;
.z80
.request syslib
;
;	+----------------------+
;	| data storage section |
;	+----------------------+
;
	dseg
;
	INCLUDE	TSHELL.DEF
;
idfcb:	db	1,'TSHELL  IDS',0,0,0,0	; password file
	ds	22
logfcb:	db	1,'TSHELL  LOG',0,0,0,0	; activity log
	ds	22
crtfcb:	db	1,'TSHELL  CRT',0,0,0,0	; crt configuration file
	ds	22
lgofcb:	db	1,'TSHELL  SCR',0,0,0,0	; logo file
	ds	22
bulfcb:	db	1,'TSHELL  BUL',0,0,0,0	; bulletin file
	ds	22
;
rqid:	db	'         '		; requested user id
rqpw:	db	'         '		; requested password
;
idsize:	dw	0			; password file size (must be < 8M)
;
retry:	db	tries			; retry counter
delay:	db	wait
;
inbuf1:	db	5
	db	0
hhmm:	db	'00:00'
;
inbuf:	db	8
ccnt:	db	0
;
@dcfld::db	'00/00/00 at ',0
mnon:	db	'nonprivileged',0
msemi:	db	'restricted',0
mfull:	db	'full access',0
;
bauds::	db	5,6,7,10,12,14,15,0ffh
	ds	9
;
actlog:
	db	1ah
actid:	ds	8			; activity log user id
actdt:	ds	4			;   date/time
actst:	ds	2			;   station
act01:	db	0			;   on/off/bad flag (1/0/FF)
actdu:	ds	2			;   drive/user
actbp:	ds	8			;   bad password given
	db	1ah,1ah,1ah,1ah,1ah,1ah	; filler
;
mstrs:	db	0			; master date reset code (c9=ok)
;
id:	db	'.tShell.'
offset:	db	0
mstoff:	db	0
;
; default buffer. this buffer is overwritten as soon
; as a valid password file is detected.
;
defbuf:	db	'UNLOGGED',2,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh
	db	'ABCDEFGHIJKLMNOP',1,1
	ds	128-($-defbuf)		; reserve 128 bytes
	ds	40			; stack space
stack	equ	$
;
;	+------------------+
;	| code begins here |
;	+------------------+
;
	cseg
;
start:	jr	.skcls			; skip past cls code
;
defcls:	db	2,1bh,'E',0,0		; default clearscreen
	'Copyright (c) 1985 S. Kluger. All Rights Reserved. '
;
.skcls:	ld	sp,stack		; set up local stack
	ld	c,8			; set abort address
	ld	de,abort		; point to any RET
	call	tfunc
	ld	de,80h
	ld	hl,id
	ld	bc,8
	ldir
	ld	bc,41
	ld	l,0
	call	tfunc
	ld	(offset),a		; save offset
	or	a
	jp	z,fatal			; fatal error if no USR FCN
	ld	bc,0fe29h		; now set reset time in master
	ld	de,0
	ld	l,0
	call	tfunc
	ld	(mstoff),a
	call	resmt
	ld	c,13			; set compatibility flags
	ld	e,0f8h
	call	tfunc
	ld	bc,41			; log off tShell
	ld	de,0ffffh
	ld	l,2
	call	getoff			; get usrsup offset
	call	tfunc
	ld	de,idfcb		; get password file
	push	de
	ld	c,35			; filesize function
	call	cfunc
	ld	hl,(idfcb+33)		; get size
	ld	(idsize),hl		; save it
	pop	de			; get fcb back
	or	a
	jp	nz,deflog		; default logon without any ado
	ld	hl,defcls		; default clearscreen
	call	crtctl
	call	print##
	cr,lf
	'tShell (c) 1985 S. Kluger, All Rights Reserved.'
	'            8-bit Station ',0
	ld	c,12			; get network address
	call	cfunc
	ld	a,d
	add	a,'A'
	call	cout##
	ld	a,'-'
	call	cout##
	ld	a,e
	call	pafdc##
	call	crlf##
	ld	de,lgofcb
	call	fi0$open##		; open for byte read
	call	z,dsplgo		; display logo if found
	ld	de,USERID		; set dma to password file template
	ld	c,26
	call	cfunc
idloop:	ld	hl,actlog+1
	ld	b,25
.zal..:	ld	(hl),0
	inc	hl
	djnz	.zal..
	call	print##			; now ask for userid
	cr,lf
	'Enter User ID  >',0
	ld	hl,rqid
	call	get8			; get up to 8 chars
	call	print##			; now ask for password
	cr,lf
	'Enter Password >',0
	ld	hl,rqpw
	call	get8n			; get up to 8 chars without echo
	ld	hl,rqid
	ld	de,actid
	ld	bc,8
	ldir				; move name to log line
	ld	de,idfcb
	call	openf			; now open password file
	ld	hl,(idsize)		; get filesize
	ld	a,h
	or	l			; if initially 0k file...
	jp	z,errlog		;   then error
.rpfl.:	dec	hl			; decrement file pointer
	ld	(idfcb+33),hl		; set file pointer
	ld	de,idfcb		; point to file
	call	rdsec			; read a sector
	jp	nz,errlog		; default logon if error
	call	match			; try to match userid/password
	ld	hl,(idfcb+33)		; get pointer
	ld	a,h
	or	l			; if not yet 0...
	jr	nz,.rpfl.		;   ...then loop
	ld	de,idfcb		; else close file
	ld	c,16
	call	cfunc
	call	print##
	cr,lf,7
	'ERROR: invalid logon',cr,lf,0
	ld	hl,rqpw
	ld	de,actbp
	ld	bc,8
	ldir				; move bad password
	ld	a,0ffh
	ld	(act01),a		; set bad flag
	call	applog			; append to log file
	ld	a,(retry)
	dec	a
	ld	(retry),a
	jp	nz,idloop
	call	print##
	cr,lf,lf
	9,9,9,'*** SECURITY ACCESS VIOLATION ***',cr,lf,lf
	'WAIT: [',0
..try.:	ld	a,(delay)
	dec	a
	ld	(delay),a
	jr	z,.kill
	call	pa3dc##
	call	print##
	']',7,7,7,7,8,8,8,8,0
	ld	c,2
	ld	de,60			; 60 ticks
	call	tfunc
	jr	..try.
;
.kill:	ld	bc,41
	ld	l,6
	call	getoff
	call	tfunc
..inf:	call	cin##
	jr	..inf
;
; attempt to match typed id/pw with the current sector
; return only if no match
;
match:	call	decryp			; decrypt sector
	ld	hl,USERID
	ld	de,rqid
	ld	b,8
	call	compb##			; compare userid
	ret	nz			; return if error
	ld	hl,PASSWD
	ld	de,rqpw
	ld	b,8
	call	compb##			; compare password
	ret	nz			; return if error
	ld	a,(LEVEL)		; get priv level
	cp	0e5h			; deleted?
	ret	z			;   yes, ignore
	ld	hl,USERID
	ld	de,defbuf		; move for update
	ld	bc,128
	ldir
	ld	de,defbuf
	ld	c,26
	call	cfunc			; set dma
	ld	c,10
	call	tfunc			; get date/time
	ld	(defbuf+(LASTON-USERID)),hl		; store date
	ld	(defbuf+(LASTON+2-USERID)),de		; store time
	ld	c,12			; get ckt/node
	call	cfunc
	ld	(defbuf+(LASTPR-USERID)),de		; store it
	call	encryp			; encrypt
	ld	de,idfcb
	call	wrsec			; write sector back
	ld	c,16
	ld	de,idfcb
	call	cfunc			; close
;
; housekeeping done, now transpose data to the
; user data block and log him on
;
	ld	hl,USERID
	ld	de,LCLID
	ld	bc,8
	ldir
	ld	a,(LEVEL)
	ld	(LCLLV),a
	ld	a,(USRCOD)
	ld	(LCLUSC),a
	ld	hl,(DRVACC)
	ld	(LCLDRA),hl
	ld	hl,(USRACC)
	ld	(LCLUSA),hl
	ld	hl,(USRACC+2)
	ld	(LCLUSA+2),hl
	ld	hl,DREDEF
	ld	de,LCLRDD
	ld	bc,16
	ldir
	ld	a,0ffh
	ld	(LCLLGD),a
	ld	a,(SHRDRV)
	ld	(LCLSHD),a
	ld	hl,(DEFPRT)
	ld	(LCLDPR),hl
	ld	a,(SCREEN)
	ld	(LCLSCM),a
	ld	a,(INITUS)		; get initial user
	ld	e,a			; put into e
	ld	a,(INITDR)		; get initial drive
	ld	d,a
	ld	(actdu),de		; save in activity log
	ld	a,1			; set on flag
	ld	(act01),a
	push	de
	call	applog
	pop	de
	ld	a,(LEVEL)		; get acl
	and	3
	cp	2			; see if full
	jr	nz,..nf.		;   no
	ld	a,80h
	or	e
	ld	e,a
..nf.:	ld	c,14
	call	tfunc
	inc	a			; see if t-logon ok
	jp	z,log.er		;   no, error!!!
	ld	de,LCLID		; set dma
	ld	c,26
	call	cfunc
	ld	de,0ffffh		; set security
	ld	bc,41
	ld	l,1
	call	getoff
	call	tfunc			; attempt tShell logon
	or	a
	jp	nz,log.er		; error!
	ld	a,(mstrs)		; see if master was date-reset
	inc	a
	jp	nz,..mrtk		;   yes, reset time ok
	call	resmt			; else try now
	inc	a
	jp	nz,..mrtk
	call	print##
	cr,lf,lf
	'Please enter:',cr,lf,0
.date.:	call	print##
	cr,'Date : [MM/DD/YY]',8,8,8,8,8,8,8,8,8,0
	ld	hl,inbuf
	call	bline##
	cp	8
	jr	nz,.date.
	call	@udcvt##		; convert date
	jr	c,.date.
	ld	de,jconv
	add	hl,de
	push	hl			; save julian date
	ld	a,' '
	ld	(@dcfld+8),a
	call	crlf##
.time.:	call	print##
	cr,'Time : [HH:MM]',8,8,8,8,8,8,0
	ld	hl,inbuf1
	call	bline##
	cp	5
	jr	nz,.time.
	ld	hl,hhmm
	call	eval10##
	push	af
	inc	hl
	call	eval10##
	pop	af
	ld	d,a
	pop	hl
	ld	b,0
	ld	c,9
	call	tfunc
	call	resmt
..mrtk:	call	print##
	cr,lf,lf
	'Logged on ',0
	ld	c,10
	call	tfunc
	call	time
	ld	hl,(LASTON)
	ld	a,h
	or	l			; ever been on?
	jr	z,.never		;   no, skip
	call	print##
	'.   Last on ',0
	ld	de,(LASTON+2)
	call	time
	call	print##
	' on terminal ',0
	ld	hl,(LASTPR)
	ld	a,'A'
	add	a,h
	call	cout##
	ld	a,'-'
	call	cout##
	ld	a,l
	call	pafdc##
.never:	call	print##
	cr,lf,lf
	'Privilege level ',0
	ld	a,(LEVEL)
	and	3
	add	a,'0'
	call	cout##
	call	print##
	' (',0
	ld	hl,mnon			; expect nonpriv
	sub	30h
	jr	z,..ppl
	ld	hl,msemi
	dec	a
	jr	z,..ppl
	ld	hl,mfull
..ppl:	call	pstr##
	call	print##
	')',cr,lf
	'Drive access: ',0
	ld	de,80h			; set dma to 80h
	ld	c,26
	call	cfunc
	ld	bc,41
	ld	de,0ffffh
	ld	l,10			; get dskast
	call	getoff
	call	tfunc
	ld	hl,80h			; hl=pointer
	ld	de,3			; de=increment
	ld	b,16			; b =count
	ld	c,0			; c =drive
.ckdr.:	ld	a,(hl)			; get access byte
	inc	a			; see if FF
	jr	z,.ckna.		;   yes, no access
	ld	a,'A'			; make drive letter
	add	a,c
	call	cout##			; print it
.ckna.:	inc	c			; bump drive
	add	hl,de			; point to next entry
	djnz	.ckdr.			; and loop till done
	call	crlf##
	ld	de,(DEFPRM)		; get default printer stuff
	ld	b,0ffh			; do not change spool drive
	ld	c,27
	call	tfunc
	ld	a,(LEVEL)		; get access codes
	and	80h			; see if menu
	jp	nz,wrmxit		;   yes, exit with warmstart
	ld	de,CMDLN		; point to command line
	ld	a,(de)			; get count
	or	a			; empty?
	jr	z,.skc..		;   yes, skip
	ld	c,18
	call	tfunc
.skc..:	jp	nwrmxt			; exit without warmstart
;
; default error logon (this should never happen, but...)
;
errlog:	call	print##
	cr,lf,lf,7
	'ERROR: munched password file? Call sysadmin.',cr,lf,lf,0
	ld	a,30
	ld	(deflog+3),a		; make logon user 30, nonpriv
;
; default logon, priv 0A:
;
deflog:	ld	c,14			; logon
	ld	de,80h			; priv level 1
	call	tfunc
	inc	a			; test error
	jp	z,log.er
	ld	de,defbuf		; point to default buffer
	ld	c,26
	call	cfunc			; set dma
	ld	bc,41			; log into tshell
	ld	de,0ffffh
	ld	l,1
	call	getoff
	call	tfunc
	or	a
	jp	nz,log.er
	call	crlf##
	rst	0
;
; subroutines
;
; display logo file
;
dsplgo:	call	f0$get##		; get a byte
	jr	nz,.dslx		; eof maybe or some other error
	and	7fh			; strip parity
	cp	1ah			; eof?
	jr	z,.dslx			;   yes
	cp	7fh			; another way to mark eof
	jr	z,.dslx			;   yes
	call	cout##			; display character
	jr	dsplgo			;   and loop
;
.dslx:	call	fi0$close##		; close file
abort:	ret
;
; get up to 8 characters
;
get8n:	ld	d,1
	jr	.g8.
;
get8:	ld	d,0
.g8.:	call	.g8zl			; clear input line
	ld	b,8			; set max count
.g8l:	call	capin##			; get a character, capitalize
	cp	' '+1			; check if space or less
	jr	nc,.g8nc		;   no, continue
	cp	8			; backspace?
	jr	z,.g8bs
	cp	7fh			; delete?
	jr	z,.g8bs
	cp	cr			; return?
	jr	nz,.g8er		;   no, error
	ld	a,8			; see if b=8
	cp	b
	ret	nz			; typed something (b<8)
.g8er:	call	error
	jr	.g8l
;
.g8nc:	bit	0,d			; see if echo on
	call	z,cout##
	ld	(hl),a
	inc	hl
	djnz	.g8l			; loop
.g8wcr:	call	capin##			; wait for cr or bs
	cp	cr
	ret	z			; return if cr
	cp	7fh
	jr	z,.g8bs			; backspace if delete key
	cp	8
	jr	z,.g8bs
	call	error
	jr	.g8wcr
;
; process backspace
;
.g8bs:	ld	a,8			; see if b=8
	cp	b
	jr	z,.g8er			; can't backspace on blank line
	inc	b			; increment counter
	dec	hl			; decrement pointer
	ld	(hl),' '		; blank out
	bit	0,d			; test echo flag
	jr	nz,.g8l			; loop back if echo off
	call	print##			; else wipe out char on screen
	8,' ',8,0
	jr	.g8l
;
; zero input line
;
.g8zl:	push	hl
	ld	b,8
.g8zll:	ld	(hl),' '
	inc	hl
	djnz	.g8zll
	pop	hl
	ret
;
log.er:	ld	b,a
	call	logerr			; display logon error message
	inc	b
	jr	z,l.ts.e
	call	print##
	'TurboDOS',0
	jp	wrmxit			; exit with warmstrt on
;
l.ts.e:	call	print##
	'tShell',0
;
; exit with warmstart enabled
;
wrmxit:	ld	e,0ffh
	jr	exit
;
; exit with warmstart disabled
;
nwrmxt:	ld	e,0
exit:	ld	c,17			; warmstart function
	call	tfunc
	call	print##
	cr,lf,lf,0
	ld	hl,USERID		; be sure to blank data area
	ld	bc,stack-USERID
.bldl:	ld	(hl),0
	inc	hl
	dec	bc
	ld	a,b
	or	c
	jr	nz,.bldl
	rst	0			; exit to tdos
;
logerr:	call	print##
	cr,lf,lf
	'ERROR: Cannot log on! Error source: ',0
error:	ld	a,7			; sound bell
	jp	cout##
;
; crt control routine
; input: hl points to string <len><byt><byt>...
; uses hl, af
;
crtctl:	ld	a,(hl)
	or	a
	ret	z			; return if null
	push	bc
	ld	b,a			; count to b
.crctl:	inc	hl
	ld	a,(hl)
	call	cout##
	djnz	.crctl
	pop	bc
	ret
;
; open file with lock
;
openf:	ld	hl,5			; point to shared flag
	add	hl,de
	ld	a,80h
	or	(hl)
	ld	(hl),a			; set shared flag
	push	de
	ld	c,15
	call	cfunc
	pop	de
	ld	hl,32
	add	hl,de
	ld	(hl),0
	or	a
	ret	z			; file is now open
	jr	openf			; else loop since we know file exists
;
; read a sector - enter with hl = sector, de = fcb
;
rdsec:	call	loksec			; lock sector
	push	de
	ld	c,33			; read
	call	cfunc
	or	a			; set error flag
	jr	fresec			; free sector
;
; write a sector - enter with hl = sector, de=fcb
;
wrsec:	call	loksec			; lock sector
	push	de			; save fcb
	ld	c,34			; write
	call	cfunc
	or	a			; set error flag
;
; free current file sector
;
fresec:	pop	de
	push	af
	ld	c,43
	call	cfunc
	pop	af
	ret
;
; lock current file sector
;
loksec:	push	de			; save fcb pointer
	ld	c,42			; attempt lock
	call	cfunc
	pop	de
	cp	8			; locked already?
	jr	z,loksec		;   yes, loop
	ret
;
; decrypt user block
;
decryp:	ld	hl,USERID
	ret
;
; encrypt default buffer
;
encryp:	ld	hl,defbuf
	ret
;
time:	push	de
	ld	de,-jconv
	add	hl,de
	call	@dcvrt##
	ld	hl,@dcfld
	call	pstr##
	pop	de
	ld	a,d
	call	..10
	ld	a,':'
	call	cout##
	ld	a,e
..10:	cp	10
	jr	nc,..10.
	push	af
	ld	a,'0'
	call	cout##
	pop	af
..10.:	jp	pafdc##
;
; append to activity log
;
applog:	ld	de,logfcb		; point to log
	ld	c,35			; filesize
	call	cfunc
	or	a
	ret	nz			; ignore file not found
	ld	c,10
	call	tfunc			; get date/time
	ld	(actdt),hl
	ld	(actdt+2),de
	ld	c,12
	call	cfunc			; get station
	ld	(actst),de
	ld	hl,(logfcb+33)
	dec	hl
	ld	(logfcb+33),hl		; decrement file pointer
	ld	de,logfcb
	call	openf			; open shared
	ld	de,80h			; set defdma
	ld	c,26
	call	cfunc
	ld	de,logfcb
	call	rdsec			; read last sector
	ld	hl,80h			; hl=pointer to def dma
	ld	de,20h			; de=byte count
..ckel:	ld	a,(hl)			; get byte
	cp	0ffh			; endmark?
	jr	z,.fe..			;   yes
	add	hl,de
	ld	a,l
	or	a
	jr	nz,..ckel		; try next entry
	ld	hl,(logfcb+33)
	inc	hl
	ld	(logfcb+33),hl
	ld	hl,80h			; set start of buffer
	push	hl
.zac.:	ld	(hl),0ffh		; blank buffer
	inc	l
	jr	nz,.zac.
	pop	hl
.fe..:	ld	de,actlog
	ex	de,hl
	ld	bc,32			; 32 bytes to be moved
	ldir
	ld	a,l			; see if end of buffer
	or	a
	jr	z,.eob.			; yes, skip
	ld	(hl),0ffh		;   else set endmark
.eob.:	ld	de,logfcb
	call	wrsec			; write the sector
	ld	de,logfcb
	ld	c,16
	jp	cfunc			; close and exit
;
getoff:	ld	a,(offset)
	add	a,l
	ld	l,a
	ret
;
; reset master reset date/time
;
resmt::	ld	a,(offset)
	add	a,16
	ld	l,a
	ld	bc,41
	call	tfunc			; get master node
	ex	de,hl
	ld	a,(mstoff)
	add	a,15
	ld	l,a
	ld	bc,0fe29h
	call	tfunc
	ld	(mstrs),a		; save master date set code
	ret
;
fatal:	call	print##
	cr,lf,lf,7
	'ERROR: tShell not installed',cr,lf,lf,0
	rst	0
	end
 dma
	ld	de,20h			; de=byte count
..ckel:	ld	a,(hl)			; get byte
	cp	0f